package com.oasys.aspect;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author mis_wu
 * @date 2022/6/13 19:52
 * @todo 日志切面处理
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    private static final ThreadLocal<Long> threadLocal = new NamedThreadLocal<>("start-time");

    /**
     * 配置切入点 controller包下的所有
     */
    @Pointcut("execution(* com.oasys.controller.*.*(..))")
    public void logPointcut() {
        // 该方法无方法体,主要为了让同类中其他方法使用此切入点
    }

    @Before("logPointcut()")
    public void doBefore(JoinPoint joinPoint){
        threadLocal.set(System.currentTimeMillis());
        //传入的是切面对象,即出发这个AOP时被调用的那个方法,以获取所需要的"调用方法"以及"传入参数"
        ServletRequestAttributes attributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String url = request.getRequestURL().toString();
        String ip = request.getRemoteAddr();
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        joinPoint.getSignature();
        String method = joinPoint.getSignature().getClass() + "." + joinPoint.getSignature().getDeclaringTypeName();
        Object[] args=joinPoint.getArgs();
        LogContent content = new LogContent(url, ip, method, args);
        log.info("请求ip地址:{}",content.getIp());
        log.info("请求地址:{}",content.getUrl());
        log.info("请求参数:{}",content.getArgs());
    }

    @AfterReturning(returning = "result", pointcut = "logPointcut()")
    public void logAfterReturning(Object result){
        Long endTime = System.currentTimeMillis();
        log.info("返回值:{}",result);
        log.info("请求耗时:{} ms", endTime - threadLocal.get());
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class LogContent{
        private String url;
        private String ip;
        private String method;
        private Object[] args;
    }

}
